﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;

using System.Windows.Forms;
using System.IO;
using System.Media;

using System.Net;           //支持网络
using System.Net.Sockets;   //支持socket
using System.Threading;     //支持多线程

namespace ChessClient
{
    //客户端状态枚举类型
    public enum ClientState
    { 
        离线 = 1, 空闲 = 2, 下挑战书 = 3, 接挑战书 = 4, 对弈 = 5
    }
    public enum Piece
    { 
        无子 = 0,
        红车 = 1, 红马 = 2, 红相 = 3, 红士 = 4, 红帅 = 5, 红炮 = 6, 红卒 = 7,
        蓝车 = 8, 蓝马 = 9, 蓝象 = 10, 蓝士 = 11, 蓝将 = 12, 蓝炮 = 13, 蓝兵 = 14
    }

    //走棋方枚举类型
    public enum Player
    { 
        无 = 0, 红 = 1, 蓝 = 2
    }
    public partial class FormMain : Form
    {   
        //客户端Socket对象，用于和服务器进行通讯
        private Socket _socketClient = null;
        //线程对象，用于客户端接受服务器数据包
        private Thread threadReceivePacket = null;

        //本地客户端IP，端口，昵称
        private IPAddress _localIP = IPAddress.Parse("0.0.0.0");
        private int _localPort = 0;
        private string _localNickName = "";
        private ClientState _localState = ClientState.离线;
        //服务器ip，端口
        private IPAddress _serverIP = IPAddress.Parse("0.0.0.0");
        private int _serverPort = 0;

        //下棋对手端IP，端口， 昵称
        private IPAddress _opponentIP = IPAddress.Parse("0.0.0.0");
        private int _opponentPort = 0;
        private string _opponentNickName = "";

        //发起挑战的对话框
        DlgSendChallenge dlgSendChallenge = null;
        //接收挑战的对话框
        DlgAcceptChallenge dlgAcceptChallenge = null;
        

        //保存象棋棋盘的所有棋子值(棋盘共10行9列，但0行0列保留不用)
        private Piece[,] _chess = new Piece[11, 10];
        
        //保存当前走棋方
        private Player _curPlayer = Player.无;
        
        //保存所有走棋步骤
        private List<Step> _stepList = new List<Step>();
        //保存棋盘左上角坐标
        private Point _leftTop = new Point(60, 60);

        //保存棋盘格子的行高和列宽
        private int _rowHeight = 60;
        private int _colWidth = 60;

        //保存棋子半径
        private int _pieceR = 29;

        //保存拾起的棋子，默认为无子
        private Piece _pickChess = Piece.无子;
        //保存拾起的棋子的行号和列号
        private int _pickRow = 0;
        private int _pickCol = 0;

        //保存落下棋子的行号和列号
        private int _dropRow = 0;
        private int _dropCol = 0;

        //保存当前鼠标所在点坐标
        private Point _curMousePoint = new Point(0, 0);
        
        //保存棋盘位图
        Bitmap _deskBmp = new Bitmap("desktop.jpg");
        
        //保存棋子位图，为了对应，[0]不用
        private Bitmap[] _pieceBmp = new Bitmap[15];
        
        //保存红方头像位图
        private Bitmap _redBmp = new Bitmap("红方头像.bmp");
        //保存蓝方头像位图
        private Bitmap _blueBmp = new Bitmap("蓝方头像.bmp");

        //自定义类方法：绘制棋盘
        public void DrawBoard(Graphics g)
        { 
            //绘制棋盘
            g.DrawImage(_deskBmp, new Point(0, 0));

            //创建粗画笔和细画笔
            Pen thickPen = new Pen(Color.Black, 6);
            Pen thinPen = new Pen(Color.Black, 2);

            //绘制棋盘外围的粗框
            int gap = (int)(_rowHeight * 0.15);
            g.DrawRectangle(thickPen, new Rectangle(_leftTop.X - gap, _leftTop.Y - gap, _colWidth * 8 + 2 * gap, _rowHeight * 9 + 2 * gap));

            //绘制棋盘的十条横线
            for (int row = 1; row <= 10; row++)
            {
                g.DrawLine(thinPen, new Point(_leftTop.X, _leftTop.Y + _rowHeight * (row - 1)),
                                    new Point(_leftTop.X + 8 * _colWidth, _leftTop.Y + _rowHeight * (row - 1)));
            }

            //绘制棋盘的九条竖线
            for (int col = 1; col <= 9; col++)
            {
                 //绘制上半部分的竖线
                 g.DrawLine(thinPen, new Point(_leftTop.X + (col - 1) * _colWidth, _leftTop.Y),
                                     new Point(_leftTop.X + (col - 1) * _colWidth, _leftTop.Y + _rowHeight * 4));
                 //绘制下半部分
                 g.DrawLine(thinPen, new Point(_leftTop.X + (col - 1) * _colWidth, _leftTop.Y + _rowHeight * 5),
                                     new Point(_leftTop.X + (col - 1) * _colWidth, _leftTop.Y + _rowHeight * 9));
            }

            //绘制楚河汉界左右两端的两条短竖线
            g.DrawLine(thinPen, new Point(_leftTop.X, _leftTop.Y + _rowHeight * 5),
                                new Point(_leftTop.X, _leftTop.Y + _rowHeight * 5));
            g.DrawLine(thinPen, new Point(_leftTop.X + _colWidth * 8, _leftTop.Y + _rowHeight * 5),
                                new Point(_leftTop.X + _colWidth * 8, _leftTop.Y + _rowHeight * 5));

            //绘制上方九宫格的交叉线
            g.DrawLine(thinPen, new Point(_leftTop.X + 3 * _colWidth, _leftTop.Y),
                                new Point(_leftTop.Y + 5 * _colWidth, _leftTop.Y + 2 * _rowHeight));
            g.DrawLine(thinPen, new Point(_leftTop.X + 5 * _colWidth, _leftTop.Y),
                                new Point(_leftTop.Y + 3 * _colWidth, _leftTop.Y + 2 * _rowHeight));
            //绘制下方九宫格
            g.DrawLine(thinPen, new Point(_leftTop.X + 3 * _colWidth, _leftTop.Y + 7 * _rowHeight),
                                new Point(_leftTop.Y + 5 * _colWidth, _leftTop.Y + 9 * _rowHeight));
            g.DrawLine(thinPen, new Point(_leftTop.X + 5 * _colWidth, _leftTop.Y + 7 * _rowHeight),
                                new Point(_leftTop.Y + 3 * _colWidth, _leftTop.Y + 9 * _rowHeight));
            
            //书写楚河汉界
            Font font1 = new Font("隶书", (float)(_rowHeight * 0.8), FontStyle.Regular, GraphicsUnit.Pixel);
            SolidBrush brush = new SolidBrush(Color.Black);
            g.DrawString("楚河", font1, brush, new Point(_leftTop.X + _colWidth, (int)(_leftTop.Y + _rowHeight * 4.1)));
            g.DrawString("汉界", font1, brush, new Point(_leftTop.X + _colWidth * 5, (int)(_leftTop.Y + _rowHeight * 4.1)));

            //书写行的数字编号
            Font font2 = new Font("黑体", (float)(_rowHeight * 0.6), FontStyle.Regular, GraphicsUnit.Pixel);
            for (int row = 1; row <= 10; row++)
                g.DrawString(row.ToString(), font2, brush, new Point((int)(_leftTop.X + _colWidth * 8.6),
                                                                     (int)(_leftTop.Y - _rowHeight * 0.4 + _rowHeight * (row - 1))));

            //书写列的数字编号
            string[] colNumber = new String[9] { "一", "二", "三", "四", "五", "六", "七", "八", "九" };
            Font font3 = new Font("黑体", (float)(_rowHeight * 0.5), FontStyle.Regular, GraphicsUnit.Pixel);
            for (int col = 1; col <= 9; col++)
                g.DrawString(colNumber[col - 1], font3, brush, new Point((int)(_leftTop.X - _colWidth * 0.3 + _colWidth * (col - 1)),
                                                                         (int)(_leftTop.Y + _rowHeight * 9.6)));
            g.DrawString("蓝方", font3, brush, new Point(_leftTop.X + 8 * _colWidth + 95, _leftTop.Y + (int)(2.2 * _rowHeight)));
            g.DrawString("红方", font3, brush, new Point(_leftTop.X + 8 * _colWidth + 95, _leftTop.Y + (int)(6.4 * _rowHeight)));

            //绘制第三行的炮营地
            DrawCampMark(g, new Point(_leftTop.Y + _colWidth * 1, _leftTop.Y + _rowHeight * 2), true, true);
            DrawCampMark(g, new Point(_leftTop.Y + _colWidth * 7, _leftTop.Y + _rowHeight * 2), true, true);
            //第四行兵的营地标志
            DrawCampMark(g, new Point(_leftTop.Y + _colWidth * 0, _leftTop.Y + _rowHeight * 3), false, true);
            DrawCampMark(g, new Point(_leftTop.Y + _colWidth * 2, _leftTop.Y + _rowHeight * 3), true, true);
            DrawCampMark(g, new Point(_leftTop.Y + _colWidth * 4, _leftTop.Y + _rowHeight * 3), true, true);
            DrawCampMark(g, new Point(_leftTop.Y + _colWidth * 6, _leftTop.Y + _rowHeight * 3), true, true);
            DrawCampMark(g, new Point(_leftTop.Y + _colWidth * 8, _leftTop.Y + _rowHeight * 3), true, false);
            //第七行兵的营地标志
            DrawCampMark(g, new Point(_leftTop.Y + _colWidth * 0, _leftTop.Y + _rowHeight * 6), false, true);
            DrawCampMark(g, new Point(_leftTop.Y + _colWidth * 2, _leftTop.Y + _rowHeight * 6), true, true);
            DrawCampMark(g, new Point(_leftTop.Y + _colWidth * 4, _leftTop.Y + _rowHeight * 6), true, true);
            DrawCampMark(g, new Point(_leftTop.Y + _colWidth * 6, _leftTop.Y + _rowHeight * 6), true, true);
            DrawCampMark(g, new Point(_leftTop.Y + _colWidth * 8, _leftTop.Y + _rowHeight * 6), true, false);
            //绘制第八行的炮营地
            DrawCampMark(g, new Point(_leftTop.Y + _colWidth * 1, _leftTop.Y + _rowHeight * 7), true, true);
            DrawCampMark(g, new Point(_leftTop.Y + _colWidth * 7, _leftTop.Y + _rowHeight * 7), true, true);

            //绘制拾子位置的标记
            DrawPickDropMark(g, _pickRow, _pickCol);
            //绘制落子位置的标记
            DrawPickDropMark(g, _dropRow, _dropCol);
            
            //在相应位置绘制头像
            if (_curPlayer == Player.蓝)
                g.DrawImage(_blueBmp, new Point(_leftTop.X + 8 * _colWidth + 95, _leftTop.Y + 1 * _rowHeight - 10));
            else if (_curPlayer == Player.红)
                g.DrawImage(_redBmp, new Point(_leftTop.X + 8 * _colWidth + 95, _leftTop.Y + 7 * _rowHeight + 10));

            //设置窗口标题
            if (_localNickName == "")
                this.Text = "中国象棋";
            else
                this.Text = "中国象棋 - [我方-" + _localNickName + "]vs[敌方-" + _opponentNickName + "]";
        }
        //自定义类方法：绘制（炮和兵）的营地标志
        public void DrawCampMark(Graphics g, Point center, Boolean drawLeft, Boolean drawRight)
        { 
            //偏移量和线段长度
            int offset = (int)(_rowHeight * 0.08), length = (int)(_rowHeight * 0.16);
            //直角点坐标
            Point corner = new Point();
            //画笔对象
            Pen thinPen = new Pen(Color.Black, 1);

            //是否需要绘制左边标志
            if (drawLeft == true)
            { 
                //绘制左上角的直角边
                corner.X = center.X - offset;
                corner.Y = center.Y - offset;
                g.DrawLine(thinPen, new Point(corner.X, corner.Y), new Point(corner.X - length, corner.Y));
                g.DrawLine(thinPen, new Point(corner.X, corner.Y), new Point(corner.X, corner.Y - length));

                //绘制左下角的直角边
                corner.X = center.X - offset;
                corner.Y = center.Y + offset;
                g.DrawLine(thinPen, new Point(corner.X, corner.Y), new Point(corner.X - length, corner.Y));
                g.DrawLine(thinPen, new Point(corner.X, corner.Y), new Point(corner.X, corner.Y + length));

            }
            if (drawRight == true)
            {
                //绘制右上角的直角边
                corner.X = center.X + offset;
                corner.Y = center.Y - offset;
                g.DrawLine(thinPen, new Point(corner.X, corner.Y), new Point(corner.X + length, corner.Y));
                g.DrawLine(thinPen, new Point(corner.X, corner.Y), new Point(corner.X, corner.Y - length));

                //绘制左下角的直角边
                corner.X = center.X + offset;
                corner.Y = center.Y + offset;
                g.DrawLine(thinPen, new Point(corner.X, corner.Y), new Point(corner.X + length, corner.Y));
                g.DrawLine(thinPen, new Point(corner.X, corner.Y), new Point(corner.X, corner.Y + length));
            }
        }
        //自定义方法绘制棋子
        public void DrawPiece(Graphics g)
        { 
            //逐行绘制棋子
            for (int row = 1; row <= 10; row++)
            {
                for (int col = 1; col <= 9; col++)
                {
                    //如果该位置存在棋子
                    if (_chess[row, col] != Piece.无子)
                    {
                        //在棋盘交点位置绘制棋子
                        
                        g.DrawImage(_pieceBmp[(int)_chess[row,col]], new Point(_leftTop.X + (col - 1) * _colWidth - _pieceR,
                                                        _leftTop.Y + (row - 1) * _rowHeight - _pieceR));
                        
                        //通过代码绘制棋子
                        //DrawPieceByCode(g, row, col, _chess[row, col]);
                    }
                }
            }
            //绘制拾起的棋子,实现随鼠标移动
            if (_pickChess != Piece.无子)
            {
                g.DrawImage(_pieceBmp[(int)_pickChess], new Point(_curMousePoint.X - _pieceR, _curMousePoint.Y - _pieceR));
            }
        }

        //自定义类方法：通过代码绘制单个棋子
        public void DrawPieceByCode(Graphics g, int row, int col, Piece chess)
        { 
            //画笔
            Pen pen;
            //实体化画刷
            SolidBrush fontBrush, circleBrush;

            //根据棋盘格子行高确定棋子半径
            _pieceR = (int)(_rowHeight * 0.45);

            //判断是否"无子"
            if (chess != Piece.无子)
            { 
                //根据所在方创建对应颜色和画笔实例
                if (chess.ToString().Substring(0, 1) == "红")
                {
                    pen = new Pen(Color.Red, 6);
                    fontBrush = new SolidBrush(Color.Red);
                }
                else
                {
                    pen = new Pen(Color.Blue, 6);
                    fontBrush = new SolidBrush(Color.Blue);
                }
                //绘制棋子外圆
                g.DrawEllipse(pen, _leftTop.X + (col - 1) * _colWidth - _pieceR, _leftTop.Y + (row - 1) * _rowHeight - _pieceR, _pieceR * 2, _pieceR * 2);
                //填充棋子外圆
                circleBrush = new SolidBrush(Color.Yellow);
                g.FillEllipse(circleBrush, _leftTop.X + (col - 1) * _colWidth - _pieceR, _leftTop.Y + (row - 1) * _rowHeight - _pieceR,
                              _pieceR * 2, _pieceR * 2);
                //书写棋子文字
                Font font = new Font("隶书", (float)(_pieceR * 1.9), FontStyle.Regular, GraphicsUnit.Pixel);
                g.DrawString(chess.ToString().Substring(1,1), font, fontBrush,
                             new Point(_leftTop.X + (col - 1) * _colWidth - (int)((_pieceR * 2.5) / 2),
                                       _leftTop.Y + (row - 1) * _rowHeight - (_pieceR * 2)/ 2));
            }
           
        }

        //自定义类方法：把鼠标点击位置转换为对应的行号和列号
        public bool ConvertPointRowCol(Point p, out int row, out int col)
        { 
            //获取与鼠标点击位置最近的棋盘交叉点的行号
            row = (p.Y - _leftTop.Y) / _rowHeight + 1;
            //如果超过一半则加一
            if (((p.Y - _leftTop.Y) % _rowHeight) >= _rowHeight / 2)
                row = row + 1;

            //获取最近的列号
            col = (p.X - _leftTop.X) / _colWidth + 1;
            //如果超过一半就加一
            if (((p.X - _leftTop.X) % _colWidth) >= _rowHeight / 2)
                col = col + 1;
            
            //获取最近的交叉点坐标
            Point chessP = new Point();
            chessP.X = _leftTop.X + _colWidth * (col - 1);
            chessP.Y = _leftTop.Y + _rowHeight * (row - 1);

            //判断是否落在棋子半径之内且在10行9列之内
            double dist = Math.Sqrt(Math.Pow(p.X - chessP.X, 2) + Math.Pow(p.Y - chessP.Y, 2));
            if ((dist <= _pieceR) && (row <= 10) && (row >= 1) && (col <= 9) && (col >= 1))
            {
                return true;
            }
            else
            {
                //行列号都设置为0，表示该次点击无效
                row = 0;
                col = 0;
                return false;
            }
        }

        //自定义类方法:绘制拾子和落子的位置的标记
        public void DrawPickDropMark(Graphics g, int row, int col)
        {
            //如果拾子或落子的位置不存在,落子结束
            if (row != 0)
            { 
                //画笔对象
                Pen pen = new Pen(Color.Yellow, 4);
                //拾子或落子的点坐标
                Point p = new Point(_leftTop.X + _colWidth * (col - 1), _leftTop.Y + _rowHeight * (row - 1));

                //在落子或拾子的四个角绘制标记
                g.DrawLine(pen, p.X - _pieceR, p.Y - _pieceR, p.X - _pieceR / 2, p.Y - _pieceR);
                g.DrawLine(pen, p.X - _pieceR, p.Y - _pieceR, p.X - _pieceR, p.Y - _pieceR / 2);

                g.DrawLine(pen, p.X + _pieceR, p.Y - _pieceR, p.X + _pieceR / 2, p.Y - _pieceR);
                g.DrawLine(pen, p.X + _pieceR, p.Y - _pieceR, p.X + _pieceR, p.Y - _pieceR / 2);

                g.DrawLine(pen, p.X - _pieceR, p.Y + _pieceR, p.X - _pieceR / 2, p.Y + _pieceR);
                g.DrawLine(pen, p.X - _pieceR, p.Y + _pieceR, p.X - _pieceR, p.Y + _pieceR / 2);

                g.DrawLine(pen, p.X + _pieceR, p.Y + _pieceR, p.X + _pieceR / 2, p.Y + _pieceR);
                g.DrawLine(pen, p.X + _pieceR, p.Y + _pieceR, p.X + _pieceR, p.Y + _pieceR / 2);
            }
        }

        //自定义类方法：播放声音文件
        public void PlaySound(String wavFile)
        { 
            //装载声音
            SoundPlayer soundPlay = new SoundPlayer(wavFile);
            //使用新线程播放声音
            soundPlay.Play();
        }

        //客户端发送点对点数据包到某个客户端
        public void ClientSendPtpPacket(string content, IPAddress toIp, int toPort)
        {
            try
            {
                //如果_socketClient不为空，且最近一次操作状态为连接
                if (_socketClient != null && _socketClient.Connected == true)
                {
                    //数据封包（格式：源ip-源端口-目的ip-目的端口-数据内容）
                    string sendPacket = _localIP.ToString() + "-" + _localPort.ToString() + "-" +
                                        toIp.ToString() + "-" + toPort.ToString() + "-" + content;
                    //通过_socketClient发送封好的数据
                    Byte[] bytePacket = System.Text.Encoding.UTF8.GetBytes(sendPacket);
                    _socketClient.Send(bytePacket);
                }
            }
            catch (Exception excep)
            {
                //MessageBox.Show(this, excep.Message, "异常", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        //客户端发送广播数据到客户端
        public void ClientSendBroadcastPacket(string content)
        {
            try
            {
                //如果socket不为空，且最后一次操作为连接
                if (_socketClient != null && _socketClient.Connected == true)
                {
                    //数据封包（格式：源ip-源端口-255.255.255.255-0-数据内容）
                    string sendPacket = _localIP.ToString() + "-" + _localPort.ToString() + "-" +
                                        IPAddress.Parse("255.255.255.255").ToString() + "-" + "0" + "-" + content;
                    //通过_socketClient发送封装好的数据包
                    Byte[] bytePacket = System.Text.Encoding.UTF8.GetBytes(sendPacket);
                    _socketClient.Send(bytePacket);
                }
            }
            catch (Exception excep)
            {
                //MessageBox.Show(this, excep.Message, "异常", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        //数据包拆包
        public bool DecodePacket(string packet, out IPAddress fromIp, out int fromPort, out IPAddress toIp, out int toPort,
                                 out string content)
        {
            //查找前四个破折号“-”的位置
            int count = 0;
            int[] pos = new int[4];
            for (int i = 0; i <= packet.Length - 1; i++)
            {
                if (packet[i] == '-')
                {
                    //保存破折号所在的位置
                    pos[count] = i;
                    count++;
                    //找到是个破折号就不再找了
                    if (count >= 4)
                        break;
                }
            }
            //判断破折号是否最够四个
            if (count == 4)
            {
                try
                {
                    //解析出数据包的ip和端口号
                    fromIp = IPAddress.Parse(packet.Substring(0, pos[0] - 0));
                    fromPort = Convert.ToInt32(packet.Substring(pos[0] + 1, pos[1] - pos[0] - 1));
                    toIp = IPAddress.Parse(packet.Substring(pos[1] + 1, pos[2] - pos[1] - 1));
                    toPort = Convert.ToInt32(packet.Substring(pos[2] + 1, pos[3] - pos[2] - 1));
                    //解析出数据包中的内容
                    content = packet.Remove(0, pos[3] + 1);
                    return true;
                }
                catch (Exception excep)
                {
                    fromIp = IPAddress.Parse("0.0.0.0");
                    fromPort = 0;
                    toIp = IPAddress.Parse("0.0.0.0");
                    toPort = 0;
                    content = "";
                    return false;
                }
            }
            else
            {
                fromIp = IPAddress.Parse("0.0.0.0");
                fromPort = 0;
                toIp = IPAddress.Parse("0.0.0.0");
                toPort = 0;
                content = "";
                return false;
            }
        } 

        //移除listviewclient的一行客户端
        public void RemoveItemFromListViewClient(IPAddress ip, int port)
        { 
            //对listviewclient进行遍历
            for (int i = 0; i <= listViewClient.Items.Count - 1; i++)
            { 
                //如果是待移除的客户行，则从listview中移除
                if (listViewClient.Items[i].SubItems[1].Text == ip.ToString()
                   && listViewClient.Items[i].SubItems[2].Text == port.ToString())
                {
                    listViewClient.Items.RemoveAt(i);
                    return;
                }
            }
        }
        
        //往listviewclient添加一行客户端
        public void AddItemToListViewClient(string nickName, IPAddress ip, int port, ClientState state)
        { 
            //对listviewclient进行遍历， 如果存在该客户端，则直接更新
            for (int i = 0; i <= listViewClient.Items.Count - 1; i++)
            { 
                //如果是待更新的客户端
                if (listViewClient.Items[i].SubItems[1].Text == ip.ToString()
                   && listViewClient.Items[i].SubItems[2].Text == port.ToString())
                {
                    listViewClient.Items[i].Text = nickName;
                    listViewClient.Items[i].SubItems[3].Text = state.ToString();
                    return;
                }
            }
            //设置item和子item的值
            ListViewItem item = new ListViewItem(nickName);
            item.SubItems.Add(ip.ToString());
            item.SubItems.Add(port.ToString());
            item.SubItems.Add(state.ToString());
            //往listviewclient中添加一条item
            listViewClient.Items.Add(item);
        }


        //更新listviewclien客户端的状态
        public void UpdateItemOfListViewClient(IPAddress ip, int port, ClientState newState)
        {
            //遍历
            for(int i = 0; i <= listViewClient.Items.Count - 1; i++)
            {
                //如果是待更新的客户端行
                if(listViewClient.Items[i].SubItems[1].Text == ip.ToString()
                   && listViewClient.Items[i].SubItems[2].Text == port.ToString())
                {
                    listViewClient.Items[i].SubItems[3].Text = newState.ToString();
                    return ;
                }
            }
        }
        
        //接收挑战对话框处理
        private void AcceptChallenge(Object objClientParam)
        { 
            //获取线程中的object参数对象值
            ClientParam clientParam = (ClientParam)objClientParam;

            //显示接受挑战对话框
            dlgAcceptChallenge = new DlgAcceptChallenge();
            dlgAcceptChallenge._infor = "[" + clientParam._nickName + "]向你发出了挑战书，你接收他的挑战吗？";
            DialogResult result = dlgAcceptChallenge.ShowDialog(this);

            //判断对话框的返回值
            if (result == DialogResult.Yes)
                //客户端发送点对点消息到对方客户端，接收挑战书
                ClientSendPtpPacket("接挑战书-" + _localNickName, clientParam._ip, clientParam._port);
            else if (result == DialogResult.No || result == DialogResult.Cancel)
            { 
                //客户端发送点对点数据包到对方客户端，挂免战牌
                ClientSendPtpPacket("挂免战牌-" + _localNickName, clientParam._ip, clientParam._port);

                //设置本地客户端的状态
                _localState = ClientState.空闲;
                //状态通报
                ClientSendBroadcastPacket("状态通报-" + _localState.ToString());
            }
        }
        
        //构造方法
        public FormMain()
        {
            InitializeComponent();
            //根据屏幕的分辨率设置行高和宽高
            _rowHeight = Screen.PrimaryScreen.Bounds.Size.Height / 14;
            _colWidth = _rowHeight;

            //设置左上角坐标
            _leftTop.Y = 2 * _rowHeight;
            _leftTop.X = _leftTop.Y;

            //棋盘的棋子初始为无子
            for (int row = 1; row <= 10; row++)
                for (int col = 1; col <= 9; col++)
                    _chess[row, col] = Piece.无子;
            //装载棋子位图
            for (int i = 1; i <= 14; i++)
            { 
                _pieceBmp[i] = new Bitmap(((Piece)i).ToString() + ".bmp");
                _pieceBmp[i].MakeTransparent(Color.White);
            }

            //设置头像透明色
            _redBmp.MakeTransparent(Color.White);
            _blueBmp.MakeTransparent(Color.White);
        }

        private void FormMain_Paint(object sender, PaintEventArgs e)
        {
            
        }
        //开局响应事件
        private void MenuItemBegin_Click(object sender, EventArgs e)
        {
            //显示提示确认框
            if (MessageBox.Show("你是否需要开局?", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            { 
                //清空走棋步骤
                _stepList.Clear();
                //设置走棋方（红方先走）
                _curPlayer = Player.红;

                //初始化为无子
                for (int row = 1; row <= 10; row++)
                    for (int col = 1; col <= 9; col++)
                        _chess[row, col] = Piece.无子;

                //初始化蓝方棋子
                _chess[1, 1] = Piece.蓝车; _chess[1, 2] = Piece.蓝马; _chess[1, 3] = Piece.蓝象;
                _chess[1, 4] = Piece.蓝士; _chess[1, 5] = Piece.蓝将; _chess[1, 6] = Piece.蓝士;
                _chess[1, 7] = Piece.蓝象; _chess[1, 8] = Piece.蓝马; _chess[1, 9] = Piece.蓝车;
                _chess[3, 2] = Piece.蓝炮; _chess[3, 8] = Piece.蓝炮;
                _chess[4, 1] = Piece.蓝兵; _chess[4, 3] = Piece.蓝兵; _chess[4, 5] = Piece.蓝兵;
                _chess[4, 7] = Piece.蓝兵; _chess[4, 9] = Piece.蓝兵;

                //初始化红方棋子
                _chess[10, 1] = Piece.红车; _chess[10, 2] = Piece.红马; _chess[10, 3] = Piece.红相;
                _chess[10, 4] = Piece.红士; _chess[10, 5] = Piece.红帅; _chess[10, 6] = Piece.红士;
                _chess[10, 7] = Piece.红相; _chess[10, 8] = Piece.红马; _chess[10, 9] = Piece.红车;
                _chess[8, 2] = Piece.红炮; _chess[8, 8] = Piece.红炮;
                _chess[7, 1] = Piece.红卒; _chess[7, 3] = Piece.红卒; _chess[7, 5] = Piece.红卒;
                _chess[7, 7] = Piece.红卒; _chess[7, 9] = Piece.红卒;

                //初始化拾起的棋子
                _pickChess = Piece.无子;
                //初始化拾起棋子的行号和列号
                _pickRow = 0;
                _pickCol = 0;
                //初始化落下棋子
                _dropRow = 0;
                _dropCol = 0;
                //使窗口失效，并发送Paint信息，从而触发Paint事件重绘棋子和棋盘
                pictureBox1.Invalidate();
                //播放声音文件
                PlaySound("Sounds\\begin.wav");
            }
        }

        private void FormMain_MouseDown(object sender, MouseEventArgs e)
        {
            
        }

        private void FormMain_MouseMove(object sender, MouseEventArgs e)
        {
            
        }
        //悔棋响应事件
        private void MenuItemUndo_Click(object sender, EventArgs e)
        {
            //有走棋才可以悔棋
            if (_stepList.Count >= 1)
            {
                //显示并判断是否点了yes
                if (MessageBox.Show("你是否需要悔棋？", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    Step lastStep = _stepList[_stepList.Count - 1];
                    //还原最后一步棋
                    _curPlayer = lastStep._Player;
                    _chess[lastStep._PickRow, lastStep._PickCol] = lastStep._PickChess;
                    _chess[lastStep._DropRow, lastStep._DropCol] = lastStep._DropChess;

                    //删除最后
                    _stepList.RemoveAt(_stepList.Count - 1);

                    //清空
                    _pickChess = Piece.无子;
                    _pickRow = 0;
                    _pickCol = 0;
                    _dropRow = 0;
                    _dropCol = 0;
                    //还有走棋步骤
                    if (_stepList.Count >= 1)
                    { 
                        //取出最后一个
                        lastStep = _stepList[_stepList.Count - 1];
                        _pickRow = lastStep._PickRow;
                        _pickCol = lastStep._PickCol;
                        _dropRow = lastStep._DropRow;
                        _dropCol = lastStep._DropCol;
                    }

                    //刷新窗口
                    pictureBox1.Invalidate();
                }
            }
        }
        
        //保存残局
        private void MenuItemSave_Click(object sender, EventArgs e)
        {
            //显示残局对话框
            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            { 
                //创建一个文件流对象
                FileStream fs = new FileStream(saveFileDialog1.FileName, FileMode.Create);
                //创建一个二进制写入流对象
                BinaryWriter bw = new BinaryWriter(fs);

                //写入当前的走棋方
                bw.Write((int)_curPlayer);
                //逐一写入棋子值
                for (int row = 1; row <= 10; row++)
                {
                    for (int col = 1; col <= 9; col++)
                    {
                        bw.Write((int)_chess[row, col]);
                    }
                }
                //写入走棋步骤数
                bw.Write(_stepList.Count);
                //逐一写入走棋步骤
                for (int i = 0; i <= _stepList.Count - 1; i++)
                {
                    bw.Write((int)_stepList[i]._Player);
                    bw.Write((int)_stepList[i]._PickChess);
                    bw.Write(_stepList[i]._PickRow);
                    bw.Write(_stepList[i]._PickCol);
                    bw.Write((int)_stepList[i]._DropChess);
                    bw.Write(_stepList[i]._DropRow);
                    bw.Write(_stepList[i]._DropCol);
                }
                //关闭文件流对象
                bw.Close();
                fs.Close();
            }
        }

        //打开残局
        private void MenuItemOpen_Click(object sender, EventArgs e)
        {
            //显示打开测试的对话框
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            { 
                //创建文件流对象用于读文件
                FileStream fs = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read);
                //创建写入流对象
                BinaryReader br = new BinaryReader(fs);

                //读取走棋方
                _curPlayer = (Player)br.ReadInt32();
                
                //读取棋子值
                for (int row = 1; row <= 10; row++)
                {
                    for (int col = 1; col <= 9; col++)
                    {
                        _chess[row, col] = (Piece)br.ReadInt32();
                    }
                }

                //读取走棋步骤
                int count = br.ReadInt32();
                //清空原有走棋步骤
                _stepList.Clear();
                //逐一读取走棋步骤
                for (int i = 0; i <= count - 1; i++)
                { 
                    //走棋步骤存在list中
                    Step step = new Step();
                    step._Player = (Player)br.ReadInt32();
                    step._PickChess = (Piece)br.ReadInt32();
                    step._PickRow = br.ReadInt32();
                    step._PickCol = br.ReadInt32();
                    step._DropChess = (Piece)br.ReadInt32();
                    step._DropRow = br.ReadInt32();
                    step._DropCol = br.ReadInt32();
                    _stepList.Add(step);
                }

                //初始化拾起棋子为无子
                _pickChess = Piece.无子;
                _pickRow = 0;
                _pickCol = 0;
                //初始化落子行列为0
                _dropRow = 0;
                _dropCol = 0;

                //关闭文件流对象
                br.Close();
                fs.Close();
                //强制刷新窗口
                pictureBox1.Invalidate();
            }
        }

        //IP地址编辑框的keypress事件的响应方法
        private void textBoxServerIP_KeyPress(object sender, KeyPressEventArgs e)
        {
            //输入小数，小点或者backspace
            if (e.KeyChar == '.' || (e.KeyChar >= '0' && e.KeyChar <= '9' || e.KeyChar == (char)Keys.Back))
                //如果e.Handle为false，则把他发送到操作系统统一处理，表示该动作有效
                e.Handled = false;
            else
                //如果e.Handle为true，则表示该事件已经处理过，取消事件
                e.Handled = true;//也可以通过e.KeyChar = (char)0处理

                
        }
        //pictureBox1的鼠标点击事件
        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            //鼠标左键下压，为拾起和落子
            if (e.Button == MouseButtons.Left)
            {
                //把点击位置转为行号列号
                int row, col;
                bool valid = ConvertPointRowCol(new Point(e.X, e.Y), out row, out col);

                //判断点击是否有效
                if (valid == true)
                {
                    //处理拾子动作（无子则为拾起，有子则为落下）
                    //当前手中无子，处于拾起动作
                    if (_pickChess == Piece.无子)
                    {
                        //当前走棋方是红,判断该位置是否有棋子可以拾起,其是否属于走棋方,(通过棋子名称的第一个字判断,棋子名称包含走棋方，则是走棋方的棋子)
                        if (_curPlayer == Player.红 && _chess[row, col] != Piece.无子 && _chess[row, col].ToString().IndexOf(_curPlayer.ToString()) == 0)
                        {
                            //保存棋子的值，行号，列号
                            _pickChess = _chess[row, col];
                            _pickRow = row;
                            _pickCol = col;

                            //清空拾子位置的棋子
                            _chess[_pickRow, _pickCol] = Piece.无子;
                            Invalidate();
                        }
                    }
                    //处理落子动作
                    else
                    {
                        //判断落子点是否是无子，或者对方棋子(即不是己方棋子)
                        if (_chess[row, col] == Piece.无子 || _chess[row, col].ToString().IndexOf(_curPlayer.ToString()) == -1)
                        {
                            //定义落子标志，默认为false，表示是否能落子
                            bool canDrop = false;
                            //一堆规则，通过则把canDrop设置为true

                            //象的走棋规则
                            if (_pickChess == Piece.蓝象)
                            {
                                //走田字，不绊脚，不过河则可以落子
                                if (Math.Abs(_pickRow - row) == 2 && Math.Abs(_pickCol - col) == 2
                                    && _chess[(_pickRow + row) / 2, (_pickCol + col) / 2] == Piece.无子 && row <= 5)
                                    canDrop = true;
                            }
                            if (_pickChess == Piece.红相)
                            {
                                //走田字，不绊脚，不过河则可以落子
                                if (Math.Abs(_pickRow - row) == 2 && Math.Abs(_pickCol - col) == 2
                                    && _chess[(_pickRow + row) / 2, (_pickCol + col) / 2] == Piece.无子 && row >= 6)
                                    canDrop = true;
                            }

                            //马的走棋规则
                            if (_pickChess == Piece.红马 || _pickChess == Piece.蓝马)
                            {
                                //横走日字，且不绊脚
                                if (Math.Abs(_pickCol - col) == 1 && Math.Abs(_pickRow - row) == 2 &&
                                    _chess[(_pickRow + row) / 2, _pickCol] == Piece.无子)
                                    canDrop = true;
                                //竖走日字，且不绊脚
                                if (Math.Abs(_pickCol - col) == 2 && Math.Abs(_pickRow - row) == 1 &&
                                    _chess[_pickRow, (_pickCol + col) / 2] == Piece.无子)
                                    canDrop = true;
                            }
                            //车的走棋规则
                            if (_pickChess == Piece.蓝车 || _pickChess == Piece.红车)
                            {
                                //横着走
                                if (_pickRow == row)
                                {
                                    //比较起点和落点的列的大小
                                    int max = col > _pickCol ? col : _pickCol;
                                    int min = col > _pickCol ? _pickCol : col;

                                    //统计路径上棋子的数量
                                    int chessNum = 0;
                                    for (int i = min + 1; i <= max - 1; i++)
                                        if (_chess[row, i] != Piece.无子)
                                            chessNum++;
                                    //路径上没棋子可以移动
                                    if (chessNum == 0)
                                        canDrop = true;
                                }
                                //竖着走
                                if (_pickCol == col)
                                {
                                    //比较起点和落点的行的大小
                                    int max = row > _pickRow ? row : _pickRow;
                                    int min = row > _pickRow ? _pickRow : row;

                                    //统计路径上棋子的数量
                                    int chessNum = 0;
                                    for (int i = min + 1; i <= max - 1; i++)
                                        if (_chess[i, col] != Piece.无子)
                                            chessNum++;
                                    //路径上没棋子可以移动
                                    if (chessNum == 0)
                                        canDrop = true;
                                }
                            }

                            //炮的走棋规则
                            if (_pickChess == Piece.蓝炮 || _pickChess == Piece.红炮)
                            {
                                //横着走
                                if (_pickRow == row)
                                {
                                    //比较起点和落点的列的大小
                                    int max = col > _pickCol ? col : _pickCol;
                                    int min = col > _pickCol ? _pickCol : col;

                                    //统计路径上棋子的数量
                                    int chessNum = 0;
                                    for (int i = min + 1; i <= max - 1; i++)
                                        if (_chess[row, i] != Piece.无子)
                                            chessNum++;
                                    //路径上没有棋子且落点为无子可以移动
                                    if (chessNum == 0 && _chess[row, col] == Piece.无子)
                                        canDrop = true;
                                    //路径上1个棋子，且落点为敌方棋子(是否是敌方棋子在前面已经判定，这里值判定是否是无子)
                                    if (chessNum == 1 && _chess[row, col] != Piece.无子)
                                        canDrop = true;
                                }
                                //竖着走
                                if (_pickCol == col)
                                {
                                    //比较起点和落点的行的大小
                                    int max = row > _pickRow ? row : _pickRow;
                                    int min = row > _pickRow ? _pickRow : row;

                                    //统计路径上棋子的数量
                                    int chessNum = 0;
                                    for (int i = min + 1; i <= max - 1; i++)
                                        if (_chess[i, col] != Piece.无子)
                                            chessNum++;
                                    if (chessNum == 0 && _chess[row, col] == Piece.无子)
                                        canDrop = true;
                                    //路径上1个棋子，且落点为敌方棋子
                                    if (chessNum == 1 && _chess[row, col] != Piece.无子)
                                        canDrop = true;
                                }
                            }

                            //红卒的走棋规则
                            if (_pickChess == Piece.红卒)
                            {
                                //没过河前只能直着走
                                if (_pickCol == col && _pickRow - row == 1)
                                    canDrop = true;
                                //过河后可以拐弯
                                else if (_pickRow <= 5 && _pickRow == row && Math.Abs(_pickCol - col) == 1)
                                    canDrop = true;
                            }
                            //蓝兵的走棋规则
                            if (_pickChess == Piece.蓝兵)
                            {
                                if (_pickCol == col && row - _pickRow == 1)
                                    canDrop = true;
                                else if (_pickRow >= 6 && _pickRow == row && Math.Abs(_pickCol - col) == 1)
                                    canDrop = true;
                            }

                            //红帅的走棋规则
                            if (_pickChess == Piece.红帅)
                            {
                                //横着走
                                if (_pickRow == row && Math.Abs(col - _pickCol) == 1 && col >= 4 && col <= 6)
                                    canDrop = true;
                                //竖着走
                                if (_pickCol == col && Math.Abs(row - _pickRow) == 1 && row >= 8 && row <= 10)
                                    canDrop = true;
                            }
                            //蓝将的走棋规则
                            if (_pickChess == Piece.蓝将)
                            {
                                //横着走
                                if (_pickRow == row && Math.Abs(col - _pickCol) == 1 && col >= 4 && col <= 6)
                                    canDrop = true;
                                //竖着走
                                if (_pickCol == col && Math.Abs(row - _pickRow) == 1 && row >= 1 && row <= 3)
                                    canDrop = true;
                            }

                            //红士的走棋规则
                            if (_pickChess == Piece.红士)
                            {
                                //横着走
                                if (_pickRow == row && Math.Abs(col - _pickCol) == 1 && col >= 4 && col <= 6)
                                    canDrop = true;
                                //竖着走
                                if (_pickCol == col && Math.Abs(row - _pickRow) == 1 && row >= 8 && row <= 10)
                                    canDrop = true;
                                //斜着走
                                if (Math.Abs(row - _pickRow) == 1 && Math.Abs(col - _pickCol) == 1 && row >= 8 && row <= 10 && col >= 4 && col <= 6)
                                    canDrop = true;
                            }
                            //蓝士的走棋规则
                            if (_pickChess == Piece.蓝士)
                            {
                                //横着走
                                if (_pickRow == row && Math.Abs(col - _pickCol) == 1 && col >= 4 && col <= 6)
                                    canDrop = true;
                                //竖着走
                                if (_pickCol == col && Math.Abs(row - _pickRow) == 1 && row >= 1 && row <= 3)
                                    canDrop = true;
                                if (Math.Abs(row - _pickRow) == 1 && Math.Abs(col - _pickCol) == 1 && row >= 1 && row <= 3 && col >= 4 && col <= 6)
                                    canDrop = true;
                            }
                            //可以落子
                            if (canDrop == true)
                            {
                                //通过Socket发送走棋步骤消息
                                if (_socketClient != null)
                                { 
                                    //构造需要发送的数据包
                                    string content = "移动棋子-" + _pickChess + _pickRow.ToString("D2") +
                                                        _pickCol.ToString("D2") + _chess[row, col] +
                                                        row.ToString("D2") + col.ToString("D2");
                                    //通过Socket发送数据包
                                    //Byte[] bytePacket = System.Text.Encoding.UTF8.GetBytes(sendPacket);
                                    //_socketClient.Send(bytePacket);
                                    ClientSendPtpPacket(content, _opponentIP, _opponentPort);
                                }
                                //保存走棋步骤到_stepList中
                                Step tempStep = new Step();
                                tempStep._Player = _curPlayer;
                                tempStep._PickChess = _pickChess;//拾起的棋子
                                tempStep._PickRow = _pickRow;
                                tempStep._PickCol = _pickCol;
                                tempStep._DropChess = _chess[row, col];//落子位置的棋子清空
                                tempStep._DropRow = row;
                                tempStep._DropCol = col;
                                _stepList.Add(tempStep);
                                //判断被吃的棋子是否为帅和将
                                if (_chess[row, col] == Piece.蓝将 || _chess[row, col] == Piece.红帅)
                                {
                                    //清空对手客户端的ip，端口号，昵称
                                    _opponentIP = IPAddress.Parse("0.0.0.0"); _opponentPort = 0; _opponentNickName = "";
                                    //设置本地客户端的状态
                                    _localState = ClientState.空闲;
                                    //广播状态
                                    ClientSendBroadcastPacket("状态通报-" + _localState.ToString());
                                    //显示消息提示框
                                    MessageBox.Show(this, "恭喜，你赢了!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                                    //播放相应声音
                                    PlaySound("Sounds\\over.wav");
                                    //最外层已经规定不能吃自己的，所以吃的肯定是对方
                                    MessageBox.Show(_curPlayer.ToString() + "方获胜", "提示",
                                        MessageBoxButtons.OK, MessageBoxIcon.Information);
                                    //禁止继续走棋
                                    _curPlayer = Player.无;
                                }
                                else
                                {
                                    //播放相应文件
                                    if (tempStep._DropChess == Piece.无子)
                                        PlaySound("Sounds\\drop.wav");
                                    else
                                        PlaySound("Sounds\\eat.wav");
                                    //交换走棋方
                                    if (_curPlayer == Player.红)
                                        _curPlayer = Player.蓝;
                                    else
                                        _curPlayer = Player.红;
                                }
                                //设置落子位置为拾起的棋子值
                                _chess[row, col] = _pickChess;
                                //清空拾起值
                                _pickChess = Piece.无子;
                                //保存落子的行号和列号
                                _dropRow = row;
                                _dropCol = col;

                                //强行刷新窗口
                                pictureBox1.Invalidate();
                            }
                        }
                    }
                }
                else
                {
                    //拾起棋子后无效点击不应该清空棋子,而是放回原位置，重新走
                    if (_pickChess != Piece.无子)
                    {
                        _chess[_pickRow, _pickCol] = _pickChess;
                        _pickChess = Piece.无子;
                        _pickCol = 0;
                        _pickRow = 0;
                        pictureBox1.Invalidate();
                    }
                    MessageBox.Show("此次点击无效");
                }
            }

            //右键下压，取消拾起的棋子
            else if (e.Button == MouseButtons.Right)
            {
                //判断是否拾起了棋子
                if (_pickChess != Piece.无子)
                {
                    //把拾子的位置设置为拾起棋子的值
                    _chess[_pickRow, _pickCol] = _pickChess;

                    //清空拾起的棋子
                    _pickChess = Piece.无子;
                    _pickRow = 0;
                    _pickCol = 0;
                    //强制刷新
                    pictureBox1.Invalidate();
                }
            }
        }
        //pictureBox1的鼠标移动事件
        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            //保存鼠标所在点
            _curMousePoint = e.Location;

            //判断是否已经拾起棋子
            if (_pickChess != Piece.无子)
            {
                pictureBox1.Invalidate();
            }
        }
        //pictureBox1的Paint的响应事件
        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            //绘制棋盘
            DrawBoard(e.Graphics);

            //绘制棋子
            DrawPiece(e.Graphics);
        }
        //登录大厅响应事件
        private void buttonLogin_Click(object sender, EventArgs e)
        {
            try
            {
                //创建客户端socket对象
                _socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //获取需要链接的服务器ip，端口号
                IPAddress serverIp = IPAddress.Parse(textBoxServerIP.Text);
                int serverPort = Convert.ToInt32(Convert.ToInt32(numericUpDownServerPort.Text));
                //创建终结点
                IPEndPoint ipEndPoint = new IPEndPoint(serverIp, serverPort);
                //与服务器建立socket链接
                _socketClient.Connect(ipEndPoint);

                //创建ClientReceivePacket线程，用于接收服务器端数据包
                threadReceivePacket = new Thread(new ThreadStart(ClientReceivePacket));
                //使线程再后台运行
                threadReceivePacket.IsBackground = true; threadReceivePacket.Start();
                //设置本地客户端的ip，端口，昵称，状态
                _localIP = ((IPEndPoint)_socketClient.LocalEndPoint).Address; 
                _localPort = ((IPEndPoint)_socketClient.LocalEndPoint).Port;
                _localNickName = textBoxNickName.Text;
                _localState = ClientState.空闲;
                //设置服务器ip，端口
                _serverIP = ((IPEndPoint)_socketClient.RemoteEndPoint).Address; _serverPort = ((IPEndPoint)_socketClient.RemoteEndPoint).Port;
                //启用相关控件
                textBoxServerIP.Enabled = false;
                numericUpDownServerPort.Enabled = false;
                textBoxNickName.Enabled = false;
                buttonLogin.Enabled = false;
                buttonLoginOut.Enabled = true;
                buttonSendChallenge.Enabled = true;
                buttonSurrender.Enabled = false;

                //发送新人报到到所有客户端
                ClientSendBroadcastPacket("新人报到-" + _localNickName);
            }
            catch (Exception excep)
            {
                MessageBox.Show(this, excep.Message, "异常", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
        //线程处理方法：客户端接收服务器数据包
        private void ClientReceivePacket()
        { 
            //循环接收数据包
            while (true)
            {
                try
                {
                    //判断socket最近一次发生或者接收操作时的连接状态
                    if (_socketClient.Connected == true)
                    {
                        //创建存放数据包的字节数组缓冲区
                        Byte[] bytePacket = new Byte[4000];
                        //接收客户端发送来的数据包，并返回接收到的数据包长度
                        int length = _socketClient.Receive(bytePacket);
                        //把Byte[]转换为string
                        String receivePacket = System.Text.Encoding.UTF8.GetString(bytePacket, 0, length);
                        
                        //对数据进行拆包，解析出ip，端口号，内容
                        IPAddress fromIp, toIp; int fromPort, toPort; string content = "";
                        bool result = DecodePacket(receivePacket, out fromIp, out fromPort, out toIp, out toPort, out content);
                        //如果数据拆包成功
                        if (result == true)
                        {
                            //判断数据包所含的指令
                            if (content.IndexOf("新人报到-") == 0)
                            { 
                                //解析出对方客户端的昵称
                                string nickName = content.Remove(0, 5);

                                //往listviewclient添加一行客户端
                                AddItemToListViewClient(nickName, fromIp, fromPort, ClientState.空闲);
                                //往listViewClient中添加客户端消息
                                //ListViewItem item = new ListViewItem(nickName);
                                //item.SubItems.Add(fromIp.ToString());
                                //item.SubItems.Add(fromIp.ToString());
                                //listViewClient.Items.Add(item);//往listViewClient中添加item
                            
                                //回复新人，客户端发送点对点到对方客户端
                                ClientSendPtpPacket("回复新人-" + _localNickName + "-" + _localState.ToString(), fromIp, fromPort);
                            }
                            else if (content.IndexOf("回复新人-") == 0)
                            { 
                                //解析出对方客户端的昵称
                                String nickName = "";
                                ClientState clientState = ClientState.空闲;
                                int pos1 = content.IndexOf("-");
                                int pos2 = content.IndexOf("-", pos1 + 1);
                                if (pos2 != -1)
                                {
                                    nickName = content.Substring(pos1 + 1, pos2 - pos1 - 1);
                                    clientState = (ClientState)Enum.Parse(typeof(ClientState), content.Substring(pos2 + 1));
                                }
                                //往listviewClient中添加客户端消息
                                AddItemToListViewClient(nickName, fromIp, fromPort, clientState);
                            }
                            else if (content.IndexOf("我开溜了-") == 0)
                            { 
                                //从listviewclient移除该客户端
                                RemoveItemFromListViewClient(fromIp, fromPort);
                            }
                            else if (content.IndexOf("下挑战书-") == 0)
                            {
                                if (_localState == ClientState.空闲)
                                {
                                    //解析出对方客户端的昵称
                                    string nickName = content.Remove(0, 5);

                                    //设置本地客户端状态
                                    _localState = ClientState.接挑战书;
                                    //广播通报自己的状态
                                    ClientSendBroadcastPacket("状态通报-" + _localState.ToString());

                                    //创建一个线程，弹出接收挑战对话框
                                    Thread threadAcceptChallenge = new Thread(AcceptChallenge);
                                    //使线程在后台运行
                                    threadAcceptChallenge.IsBackground = true;

                                    //设置线程参数
                                    ClientParam clientParam = new ClientParam();
                                    clientParam._ip = fromIp; clientParam._port = fromPort; clientParam._nickName = nickName;
                                    //启动该线程，并传递相关参数
                                    threadAcceptChallenge.Start(clientParam);
                                }
                                else
                                    //客户端发送点对地消息到客户端，挂免战牌
                                    ClientSendPtpPacket("我正在忙-" + _localNickName, fromIp, fromPort);
                            }
                            else if (content.IndexOf("接挑战书-") == 0)
                            { 
                                //解析出对方客户端的昵称
                                string nickName = content.Remove(0, 5);
                                //保存对手的IP，端口，昵称
                                _opponentIP = fromIp; _opponentPort = fromPort;
                                _opponentNickName = nickName;
                                //设置本地客户端状态
                                _localState = ClientState.对弈;
                                //状态通报
                                ClientSendBroadcastPacket("状态通报-" + _localState.ToString());
                                //关闭发送挑战对话框
                                if (dlgSendChallenge != null)
                                {
                                    dlgSendChallenge.DialogResult = DialogResult.Ignore;
                                    dlgSendChallenge.Close();
                                }
                                //客户端发送点对点数据包给对方，对方先走
                                ClientSendPtpPacket("你先走棋-" + _localNickName, fromIp, fromPort);
                                //模拟开局点击
                                MenuItemBegin.PerformClick();
                                //开始下象棋（蓝色先走）
                                _curPlayer = Player.蓝;
                                //播放声音
                                PlaySound("Sounds\\begin.wav");
                                //刷新
                                pictureBox1.Invalidate();
                            }
                            else if (content.IndexOf("你先走棋-") == 0)
                            { 
                                //解析出对方客户端昵称
                                string nickName = content.Remove(0, 5);
                                //保存对手ip，端口，昵称
                                _opponentIP = fromIp;
                                _opponentPort = fromPort;
                                _opponentNickName = nickName;

                                //设置本地客户端状态
                                _localState = ClientState.对弈;
                                //状态通报
                                ClientSendBroadcastPacket("状态通报-" + _localState.ToString());
                                //模拟开局点击
                                MenuItemBegin.PerformClick();
                                //开始下象棋（红方先走）
                                _curPlayer = Player.红;
                                //播放声音文件
                                PlaySound("Sounds\\begin.wav");
                                //刷新
                                pictureBox1.Invalidate();
                            }
                            else if(content.IndexOf("放弃挑战-") == 0)
                            {
                                //解析出对方客户端昵称
                                string nickName = content.Remove(0,5);

                                //关闭接收挑战对话框
                                if(dlgAcceptChallenge != null)
                                {
                                    dlgAcceptChallenge.DialogResult = DialogResult.Ignore;
                                    dlgAcceptChallenge.Close();
                                }
                                //清空对手ip，端口，昵称
                                _opponentIP = IPAddress.Parse("0.0.0.0"); _opponentPort = 0; _opponentNickName = "";

                                //设置本地客户端状态
                                _localState = ClientState.空闲;
                                //状态通报
                                ClientSendBroadcastPacket("状态通报-" + _localState.ToString());

                                //显示提示对话框
                                MessageBox.Show(this, "[" + nickName + "]放弃挑战了！","提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                                //清空象棋
                                //棋盘的棋子初始为无子
                                for (int row = 1; row <= 10; row++)
                                    for (int col = 1; col <= 9; col++)
                                        _chess[row, col] = Piece.无子;
                                pictureBox1.Invalidate();
                            }
                            else if(content.IndexOf("挂免战牌-") == 0)
                            {
                                //解析出对方客户端的昵称
                                string nickName = content.Remove(0, 5);
                                //设置本地客户端状态
                                _localState = ClientState.空闲;
                                //状态通报
                                ClientSendBroadcastPacket("状态通报-" + _localState.ToString());

                                //关闭发送挑战对话框
                                if(dlgSendChallenge != null)
                                {
                                    dlgSendChallenge.DialogResult = DialogResult.Ignore;
                                    dlgSendChallenge.Close();
                                }
                                //显示消息提示
                                MessageBox.Show(this, "[" + nickName + "]高挂免战牌，不敢迎战。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            }
                            else if(content.IndexOf("我正在忙-") == 0)
                            {
                                //解析出对方的客户端的昵称
                                string nickName = content.Remove(0, 5);

                                //设置状态消息
                                _localState = ClientState.空闲;
                                //状态通报
                                ClientSendBroadcastPacket("状态通报-" + _localState.ToString());

                                //关闭挑战对话框
                                if(dlgSendChallenge != null)
                                {
                                    dlgSendChallenge.DialogResult = DialogResult.Ignore;
                                    dlgSendChallenge.Close();
                                }
                                //显示消息提示
                                MessageBox.Show(this, "[" + nickName + "]正在忙，没空迎战", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            }
                            else if (content.IndexOf("移动棋子-") == 0)
                            {
                                //获取对方发过来的走棋步骤信息,并进行相应转换
                                string pickPiece = content.Substring(5, 2);
                                if (pickPiece == "红帅") pickPiece = "蓝将";
                                else if (pickPiece == "红卒") pickPiece = "蓝兵";
                                else if (pickPiece == "红相") pickPiece = "蓝象";
                                else if (pickPiece.Substring(0, 1) == "红") pickPiece = "蓝" + pickPiece.Substring(1, 1);
                                else if (pickPiece == "蓝将") pickPiece = "红帅";
                                else if (pickPiece == "蓝兵") pickPiece = "红卒";
                                else if (pickPiece == "蓝相") pickPiece = "红相";
                                else if (pickPiece.Substring(0, 1) == "蓝") pickPiece = "红" + pickPiece.Substring(1, 1);

                                int pickRow = 11 - Convert.ToInt32(content.Substring(7, 2));
                                int pickCol = 10 - Convert.ToInt32(content.Substring(9, 2));

                                string dropPiece = content.Substring(11, 2);
                                if (dropPiece == "红帅") dropPiece = "蓝将";
                                else if (dropPiece == "红卒") dropPiece = "蓝兵";
                                else if (dropPiece == "红相") dropPiece = "蓝象";
                                else if (dropPiece.Substring(0, 1) == "红") dropPiece = "蓝" + dropPiece.Substring(1, 1);
                                else if (dropPiece == "蓝将") dropPiece = "红帅";
                                else if (dropPiece == "蓝兵") dropPiece = "红卒";
                                else if (dropPiece == "蓝象") dropPiece = "红相";
                                else if (dropPiece.Substring(0, 1) == "蓝") dropPiece = "红" + dropPiece.Substring(1, 1);

                                int dropRow = 11 - Convert.ToInt32(content.Substring(13, 2));
                                int dropCol = 10 - Convert.ToInt32(content.Substring(15, 2));

                                //清空拾起棋子的棋子值
                                _chess[pickRow, pickCol] = Piece.无子;
                                //设置落子位置的棋子值
                                _chess[dropRow, dropCol] = (Piece)Enum.Parse(typeof(Piece), pickPiece);
                                //判断被吃的棋子是否为帅
                                if (dropPiece.IndexOf("帅") != -1)
                                {
                                    //停止走棋
                                    _curPlayer = Player.无;
                                    //清空对手客户端ip，端口号，昵称
                                    _opponentIP = IPAddress.Parse("0.0.0.0"); _opponentPort = 0; _opponentNickName = "";
                                    //设置本地客户端状态
                                    _localState = ClientState.空闲;
                                    //广播自己状态
                                    ClientSendBroadcastPacket("状态通报-" + _localState.ToString());
                                    //显示提示消息框
                                    MessageBox.Show(this, "不好意思，你输了", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                                }
                                else
                                {
                                    //交换走棋方
                                    if (_curPlayer == Player.红) _curPlayer = Player.蓝;
                                    else if (_curPlayer == Player.蓝) _curPlayer = Player.红;
                                }
                                //重绘制
                                pictureBox1.Invalidate();
                            }
                        }
                    }
                    else
                        return; 
                }
                catch (Exception excep)
                {
                    //MessageBox.Show(this, excep.Message, "异常", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
           
        }

        //退出大厅
        private void buttonLoginOut_Click(object sender, EventArgs e)
        {
            //显示确认消息框
            if (MessageBox.Show(this, "需要退出大厅吗？", "请确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                try
                {
                    //客户端发送广播数据“我开溜了-”到所有客户端
                    ClientSendBroadcastPacket("我开溜了-" + _localNickName);
                    //清空本地客户端的IP,端口号，昵称
                    _localIP = IPAddress.Parse("0.0.0.0"); _localPort = 0; _localNickName = ""; _localState = ClientState.离线;
                    //清空服务器的ip，端口
                    _serverIP = IPAddress.Parse("0.0.0.0"); _serverPort = 0;
                    //启用或禁用相关控件
                    textBoxServerIP.Enabled = true; numericUpDownServerPort.Enabled = true; textBoxNickName.Enabled = true;
                    buttonLogin.Enabled = true; buttonLoginOut.Enabled = false; buttonSendChallenge.Enabled = false;
                    buttonSurrender.Enabled = false;
                    //清空listviewclient
                    listViewClient.Items.Clear();
                    //象棋初始化
                    _chess.Initialize();

                    //关闭有关socket
                    if (_socketClient != null)
                        _socketClient.Close();
                    //结束线程
                    if (threadReceivePacket != null)
                        threadReceivePacket.Abort();
                }
                catch (Exception excep)
                {
                    //MessageBox.Show(this, excep.Message, "异常", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        //窗口关闭事件
        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            //显示确认提示框
            if (MessageBox.Show(this, "需要关闭程序吗？", "请确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                //取消窗口关闭
                e.Cancel = true;
            else
            {
                try
                {
                    //客户端发送广播数据包“我开溜-”到所有客户端
                    ClientSendBroadcastPacket("我开溜了-" + _localNickName);

                    //关闭所有相关的socket
                    if (_socketClient != null && _socketClient.Connected == true)
                        _socketClient.Close();
                    //结束线程
                    if (threadReceivePacket != null)
                        threadReceivePacket.Abort();
                }
                catch (Exception excep)
                { 
                    MessageBox.Show(this, excep.Message, "异常", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }


        //下挑战书
        private void buttonSendChallenge_Click(object sender, EventArgs e)
        {
            //判断本地客户端状态
            if (_localState == ClientState.空闲)
            { 
                //判断是否选择了想挑战的客户端
                if (listViewClient.SelectedItems.Count == 0)
                {
                    MessageBox.Show(this, "请先在用户列表选择你要挑战的对手", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }

                //获取将要挑战的对手的IP，端口号，昵称
                IPAddress opponentIp = IPAddress.Parse(listViewClient.SelectedItems[0].SubItems[1].Text);
                int opponentPort = Convert.ToInt32(listViewClient.SelectedItems[0].SubItems[2].Text);
                string opponentNickName = listViewClient.SelectedItems[0].Text;

                //判断是否向自己挑战
                try
                {
                    //客户端发送点对点数据到想要挑战的客户端
                    ClientSendPtpPacket("下挑战书-" + _localNickName, opponentIp, opponentPort);

                    //设置本地客户端的状态
                    _localState = ClientState.下挑战书;
                    //客户端发送广播数据包到所有客户端，通报自己的状态
                    ClientSendBroadcastPacket("状态通报-" + _localState.ToString());
                    //显示发送挑战对话框
                    dlgSendChallenge = new DlgSendChallenge();
                    dlgSendChallenge._infor = "你已经向[" + opponentNickName + "]发出了挑战书，请耐心等待对方回应？";
                    //判断是否需要撤回挑战书
                    if (dlgSendChallenge.ShowDialog(this) == DialogResult.Cancel)
                    { 
                        //清空挑战框对话框
                        dlgSendChallenge = null;

                        //客户端发送点对点数据包到想挑战的客户端，放弃挑战
                        ClientSendPtpPacket("放弃挑战-" + _localNickName.ToString(), opponentIp, opponentPort);
                        //设置本地客户端的状态
                        _localState = ClientState.空闲;
                        //在listviewclient中更新客户端的状态
                        UpdateItemOfListViewClient(_localIP, _localPort, _localState);

                        //发送广播数据到所有客户端，进行状态通报
                        ClientSendBroadcastPacket("状态通报-" + _localState.ToString());
                    }
                }
                catch (Exception excep)
                {
                    //MessageBox.Show(this,excep.Message, "异常", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            else
                MessageBox.Show(this, "你现在忙，不能下挑战书！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

    }
}
